/**
 * exponencial.cpp
 * Autores: Danilo S. Carvalho	- 107390588
 * 			Taísa L. Martins	- 107362828 
 *
 */

#include "exponencial.h"

namespace SimuladorAD {
    Rng::Rng() {
        m_semente = gerar_semente();
        // Inicia o gerador dSFMT com a semente m_semente.
        dsfmt_init_gen_rand(&m_estado,(uint32_t)m_semente); 
    }
    
    Rng::Rng(unsigned long semente) {
        m_semente = semente;
        // Inicia o gerador dSFMT com a semente m_semente.
        dsfmt_init_gen_rand(&m_estado, (uint32_t)m_semente);
    }
    
    Rng::Rng(unsigned long semente, dsfmt_t estado) {
        m_semente = semente;
        m_estado = estado;
    }

    unsigned long Rng::gerar_semente() {
// Para compilar no Windows 
#ifdef _WIN32
        LARGE_INTEGER tick;
        
        srand(time(NULL));
        QueryPerformanceCounter(&tick); 
        return (unsigned long)tick.QuadPart * rand();
        rand
// Paa compilar no Linux (Unix)
#else
        struct timeval t_semente;

		srand(time(NULL));
        gettimeofday(&t_semente, NULL);
        return t_semente.tv_usec * rand();
#endif       
    }

    dsfmt_t Rng::estado() const {
        return m_estado;
    }

    double Rng::semente() const {
        return m_semente;
    }

    double Rng::gerar() {
		// Usa a função dsfmt_genrand_close_open para gerar o número (double)
		// no intervalo [0, 1).
        return dsfmt_genrand_close_open(&m_estado);
    }

	

    Exponencial::Exponencial(double taxa) {
        m_taxa = taxa;
        m_deterministico = false;
        m_gerador = new Rng();
    }

    Exponencial::Exponencial(double taxa, unsigned long semente, bool deterministico) {
        m_taxa = taxa;
        m_gerador = new Rng(semente);
        m_deterministico = deterministico;
    }
    
    Exponencial::Exponencial(double taxa, bool deterministico, Rng *gerador) {
        m_taxa = taxa;
        m_deterministico = deterministico;
        m_gerador = gerador;  
    }

    Exponencial::~Exponencial() {
        delete m_gerador;
    }

    double Exponencial::inversa_cumulativa(double u0) {
        return (-1) * (log(1 - u0) / m_taxa); // Função inversa da PDF da exponencial.
    }

    double Exponencial::semente() {
        return m_gerador->semente();
    }

    void Exponencial::deterministico(bool ativado) {
        m_deterministico = ativado;
    }

    double Exponencial::gera_amostra() {
        if (m_deterministico) return 1 / m_taxa; // No modo determinístico, retorna a constante 1/lambda.

        return inversa_cumulativa(m_gerador->gerar());
    }
}
